package com.haiqiu.system.service.impl;

import com.haiqiu.common.exception.BaseException;
import com.haiqiu.common.page.PageRequest;
import com.haiqiu.common.page.PageResponse;
import com.haiqiu.common.result.Constants;
import com.haiqiu.common.utils.tools.StringUtil;
import com.haiqiu.common.utils.web.JwtTokenUtil;
import com.haiqiu.common.utils.web.RedisUtil;
import com.haiqiu.common.utils.web.ServletUtil;
import com.haiqiu.system.entity.SysPermission;
import com.haiqiu.system.entity.SysRole;
import com.haiqiu.system.entity.vo.MenuVo;
import com.haiqiu.system.entity.vo.MetaVo;
import com.haiqiu.system.entity.vo.RouterVo;
import com.haiqiu.system.mapper.SysPermissionMapper;
import com.haiqiu.system.mapper.SysRoleMapper;
import com.haiqiu.system.service.SysPermissionService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author HaiQiu
 * @date 2021/4/3 0:30
 * @desc
 **/
@Service
public class SysPermissionServiceImpl implements SysPermissionService {

    @Autowired
    private SysPermissionMapper sysPermissionMapper;

    @Autowired
    private SysRoleMapper sysRoleMapper;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;


    @Autowired
    private RedisUtil redisUtil;


    /**
     * 删除单个权限
     *
     * @param id
     * @return
     */
    @Override
    public void deleteByPrimaryKey(Long id) {
        if (StringUtils.isEmpty(id)) {
            throw new BaseException(Constants.ID_EXITS);
        }
        if (sysPermissionMapper.deleteByPrimaryKey(id) == 0) {
            throw new BaseException(Constants.FAIL_DEL);
        }
        delRedisAuthList();
    }


    /**
     * 新增(权限)
     *
     * @param sysPermission
     * @return
     */
    @Override
    public void save(SysPermission sysPermission) {
        //设置默认值
        setDefault(sysPermission);
        sysPermission.setCreateTime(new Date());
        if (sysPermissionMapper.insert(sysPermission) == 0) {
            throw new BaseException(Constants.FAIL_ADD);
        }
        delRedisAuthList();
    }

    /**
     * 设置新增的默认值
     *
     * @param sysPermission 修改实体
     */
    private void setDefault(SysPermission sysPermission) {
        if (!(sysPermission.getType().equals(Constants.MENU_TYPE_CATALOGUE)
                || sysPermission.getType().equals(Constants.MENU_TYPE_MENU)
                || sysPermission.getType().equals(Constants.MENU_TYPE_BUTTON)
        )) {
            throw new BaseException("菜单类型参数错误");
        }
        // 如果父级没有传ID，默认为最高父级
        if (sysPermission.getParentId() == null) {
            sysPermission.setParentId(Constants.MENU_PARENT_ID);
        }
        // 如果是父级，默认组件为#
        if (sysPermission.getParentId() == Constants.MENU_PARENT_ID) {
            sysPermission.setComponent("#");
        }
        //如果不是外链并且是父级菜单，添加/
        if (sysPermission.getParentId() == Constants.MENU_PARENT_ID
                && !sysPermission.getPath().startsWith("/")
                && !sysPermission.getPath().startsWith("http")) {
            sysPermission.setPath("/" + sysPermission.getPath().trim());
        }
        // 如果不是按钮且路由组件不是/开头，移除/
        if (!sysPermission.getType().equals(Constants.MENU_TYPE_BUTTON) && sysPermission.getComponent().startsWith("/")) {
            String component = sysPermission.getComponent().substring(sysPermission.getComponent().indexOf("/") + 1);
            sysPermission.setComponent(component);
        }
        // 如果新增的类型为菜单且不是按钮和目录，也不是顶级，路由开头有“/”，则应该加上“/”
        if (sysPermission.getType().equals(Constants.MENU_TYPE_MENU)
                && sysPermission.getPath().startsWith("/")
                && sysPermission.getParentId() != Constants.MENU_PARENT_ID) {
            String path = sysPermission.getPath().substring(sysPermission.getPath().indexOf("/") + 1);
            sysPermission.setPath(path);
        }
        // 新增的菜单为按钮类型，则图标默认初始值为#，设置请求api地址为/开头
        if (sysPermission.getType().equals(Constants.MENU_TYPE_BUTTON)) {
            sysPermission.setIcon("#");
            sysPermission.setPath(!sysPermission.getPath().startsWith("/") ? "/" + sysPermission.getPath() : sysPermission.getPath());
        }
        //新增默认激活
        if (sysPermission.getId() == null) {
            sysPermission.setActive(true);
        }
        //新增类型为菜单和目录时，请求方法默认设置为空
        if (sysPermission.getType().equals(Constants.MENU_TYPE_CATALOGUE) || sysPermission.getType().equals(Constants.MENU_TYPE_MENU)) {
            sysPermission.setMethod(null);
        }
        sysPermission.setUpdateTime(new Date());

    }

    /**
     * 根据ID查询(权限)
     *
     * @param id
     * @return
     */
    @Override
    public SysPermission get(Long id) {
        SysPermission sysPermission = sysPermissionMapper.selectByPrimaryKey(id);
        if (sysPermission == null) {
            throw new BaseException(Constants.DATA_EXIT);
        }
        return sysPermission;
    }


    /**
     * 修改(权限)
     *
     * @param sysPermission
     * @return
     */
    @Override
    public void update(SysPermission sysPermission) {
        //设置默认值
        setDefault(sysPermission);
        if (sysPermissionMapper.updateByPrimaryKeySelective(sysPermission) == 0) {
            throw new BaseException(Constants.FAIL_UPDATE);
        }
        delRedisAuthList();
    }

    public void delRedisAuthList() {
        Set<String> keysByAuth = redisUtil.getKeys(Constants.REDIS_USER_AUTH);
        redisUtil.del(keysByAuth);
        Set<String> keysByUser = redisUtil.getKeys(Constants.REDIS_USER);
        redisUtil.del(keysByUser);
    }


    /**
     * 根据用户名查询权限
     *
     * @param username
     * @return
     */
    @Override
    public List<String> selectAuthListByUsername(String username) {
        //判断是否为超级管理员
        if (username.equals(Constants.ADMIN)) {
            List<SysPermission> sysPermissionList = sysPermissionMapper.all();
            return sysPermissionList.stream().map(SysPermission::getValue).collect(Collectors.toList());
        }
        return sysPermissionMapper.selectAuthListByUsername(username);
    }


    /**
     * 获取权限菜单
     *
     * @param username
     * @return
     */
    @Override
    public List<SysPermission> selectPermissionListByUsername(String username) {
        List<SysPermission> list;
        if (username.equals(Constants.ADMIN)) {
            list = sysPermissionMapper.all();
        } else {
            list = sysPermissionMapper.selectPermissionListByUsername(username);
        }
        return list;
    }


    /**
     * 组装前端格式的路由菜单
     *
     * @return 菜单集合
     */
    @Override
    public List<RouterVo> menu() {
        HttpServletRequest request = ServletUtil.getHttpServletRequest();
        String username = jwtTokenUtil.getUsername(request);
        List<SysPermission> sysPermissionList = new LinkedList<>();
        if (username.equals(Constants.ADMIN)) {
            sysPermissionList = sysPermissionMapper.all();
        } else {
            sysPermissionList = sysPermissionMapper.getMenuByUsername(username);
        }
        return getMenuVos(sysPermissionList);
    }


    //*****************************递归开始********************************//

    /**
     * 递归开始，找到一级目录
     *
     * @param menuVoList
     * @return
     */
    public List<MenuVo> selectMenuTreeList(List<MenuVo> menuVoList) {
        List<MenuVo> finalMenuList = new ArrayList<>();
        for (MenuVo menuVo : menuVoList) {
            if (menuVo.getParentId() == Constants.MENU_PARENT_ID) {
                finalMenuList.add(selectChildrenTreeList(menuVo, menuVoList));
            }
        }

        return finalMenuList;
    }


    /**
     * 找到一级下的所有子菜单
     *
     * @param menuVo
     * @param menuList
     * @return
     */
    public MenuVo selectChildrenTreeList(MenuVo menuVo, List<MenuVo> menuList) {
        menuVo.setChildren(new ArrayList<>());
        for (MenuVo menu : menuList) {
            if (menu.getParentId().equals(menuVo.getId())) {
                if (menuVo.getChildren() == null) {
                    menuVo.setChildren(new ArrayList<>());
                }
                menuVo.getChildren().add(selectChildrenTreeList(menu, menuList));
            }
        }
        return menuVo;
    }

    //*****************************递归结束********************************//


    /**
     * 树形权限集合
     *
     * @return
     */
    @Override
    public List<MenuVo> tree() {
        List<SysPermission> sysPermissions = sysPermissionMapper.menuAll();
        List<MenuVo> menuVoList = new ArrayList<>();
        for (SysPermission sysPermission : sysPermissions) {
            MenuVo menuVo = new MenuVo();
            BeanUtils.copyProperties(sysPermission, menuVo);
            menuVoList.add(menuVo);
        }
        return selectMenuList(menuVoList);
    }


    /**
     * 批量激活(权限)
     *
     * @param sysPermissions ID集合
     * @return 成功条数
     */
    @Override
    public int active(List<SysPermission> sysPermissions) {
        if (sysPermissions.size() == 0) {
            throw new BaseException("ID不能为空");
        }
        return sysPermissionMapper.active(sysPermissions);
    }


    @Override
    public PageResponse<MenuVo> treeList(PageRequest<SysPermission> request) {
        SysPermission sysPermission = StringUtil.checkObjFieldIsNull(request.getParams());
        long count = sysPermissionMapper.countTree(sysPermission);
        PageResponse<MenuVo> response = new PageResponse<>();
        response.setPageIndex(request.getPageIndex());
        response.setPageSize(request.getPageSize());
        response.setTotal(count);
        if (count > 0) {
            List<SysPermission> sysPermissions = sysPermissionMapper.listTree(sysPermission, request.getOffset(), request.getPageSize());
            response.setData(this.children(sysPermissions));
        }
        return response;
    }

    @Override
    public List<SysPermission> menuList(SysPermission sysPermission) {
        return sysPermissionMapper.menuList(sysPermission);
    }

    @Override
    public Map<String, Object> roleMenuTreeSelect(Long roleId) {
        List<SysPermission> sysPermissionList = sysPermissionMapper.getMenuByRoleId(roleId);
        // 选中的ID
        Set<Long> checkedKeys = sysPermissionList.stream().map(SysPermission::getId).collect(Collectors.toSet());
        Map<String, Object> map = new HashMap<>(6);
        map.put("menus", this.tree());
        map.put("checkedKeys", checkedKeys);
        return map;
    }


    public List<MenuVo> children(List<SysPermission> sysPermissions) {
        List<MenuVo> menuVoList = new ArrayList<>();
        List<SysPermission> all = all();
        List<MenuVo> menuVos = new ArrayList<>();
        for (SysPermission sysPermission : all) {
            MenuVo menuVo = new MenuVo();
            BeanUtils.copyProperties(sysPermission, menuVo);
            menuVos.add(menuVo);
        }
        for (SysPermission sysPermission : sysPermissions) {
            MenuVo menuVo = new MenuVo();
            BeanUtils.copyProperties(sysPermission, menuVo);
            menuVoList.add(selectChildrenList(menuVo, menuVos));
        }
        return menuVoList;
    }


    /**
     * 转换集合类型
     *
     * @param sysPermissions 原始集合
     * @return List<RouterVo> 树形新集合
     */
    private List<RouterVo> getMenuVos(List<SysPermission> sysPermissions) {
        List<RouterVo> routerList = new ArrayList<>();
        for (SysPermission menuVo : sysPermissions) {
            RouterVo router = new RouterVo();
            router.setId(menuVo.getId());
            router.setParentId(menuVo.getParentId());
            router.setComponent("#".equals(menuVo.getComponent()) ? "Layout" : menuVo.getComponent());
            MetaVo meta = new MetaVo(menuVo.getTitle(), menuVo.getIcon(), false, null);
            router.setMeta(meta);
            router.setPath(menuVo.getPath());
            router.setHidden(Constants.OFF);
            router.setName(menuVo.getTitle());
            if (menuVo.getPath().startsWith("http") && menuVo.getIsFrame()) {
                router.getMeta().setLink(menuVo.getPath());
            }
            if (!menuVo.getType().equals(Constants.MENU_TYPE_BUTTON)){
                routerList.add(router);
            }
        }
        return selectRouterList(routerList);
    }


    //*****************************递归开始********************************//

    /**
     * 递归开始，找到一级目录
     *
     * @param menuVoList
     * @return
     */
    public List<RouterVo> selectRouterList(List<RouterVo> menuVoList) {
        List<RouterVo> finalMenuList = new ArrayList<>();
        for (RouterVo menuVo : menuVoList) {
            if (menuVo.getParentId() == Constants.MENU_PARENT_ID) {
                finalMenuList.add(createChildRouter(menuVo, menuVoList));
            }
        }

        return finalMenuList;
    }


    /**
     * 找到一级下的所有子菜单
     *
     * @param routerVo
     * @param menuList
     * @return
     */
    public RouterVo createChildRouter(RouterVo routerVo, List<RouterVo> menuList) {
        routerVo.setChildren(new ArrayList<>());
        for (RouterVo menu : menuList) {
            if (menu.getParentId().equals(routerVo.getId())) {
                if (menu.getChildren() != null && menu.getChildren().size() != 0) {
                    menu.setRedirect("noRedirect");
                } else {
                    menu.setAlwaysShow(false);
                    menu.setRedirect(menu.getPath());
                }
                if (routerVo.getChildren() == null) {
                    routerVo.setChildren(new ArrayList<>());
                }
                routerVo.getChildren().add(createChildRouter(menu, menuList));
            }
        }
        return routerVo;
    }

    //*****************************递归结束********************************//

    /**
     * 模糊分页(权限)
     *
     * @param request
     * @return
     */
    @Override
    public PageResponse<SysPermission> list(PageRequest<SysPermission> request) {
        SysPermission sysPermission = StringUtil.checkObjFieldIsNull(request.getParams());
        long count = sysPermissionMapper.count(sysPermission);
        PageResponse<SysPermission> response = new PageResponse<>();
        response.setPageSize(request.getPageSize());
        response.setPageIndex(request.getPageIndex());
        response.setTotal(count);
        if (count > 0) {
            List<SysPermission> list = sysPermissionMapper.list(sysPermission,
                    request.getOffset(), request.getPageSize());
            response.setData(list);
        }
        return response;
    }


    /**
     * 查询所有(权限)
     *
     * @return
     */
    @Override
    public List<SysPermission> all() {
        return sysPermissionMapper.all();
    }


    /**
     * 批量删除(权限)
     *
     * @param ids
     * @return
     */
    @Override
    public int delete(Set<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            throw new BaseException(Constants.ID_EXITS);
        }
        for (Long id : ids) {
            SysPermission sysPermission = sysPermissionMapper.selectByPrimaryKey(id);
            List<SysPermission> sysPermissionList = sysPermissionMapper.selectByParentId(id);
            if (sysPermissionList != null && sysPermissionList.size() != 0) {
                throw new BaseException(String.format("%s下绑定有数据，请先删除子级", sysPermission.getTitle()));
            }
            List<SysRole> sysRoles = sysRoleMapper.selectRoleByMenuId(id);
            if (!CollectionUtils.isEmpty(sysRoles) && sysRoles.size() != 0) {
                throw new BaseException(String.format("%s下绑定有角色%s数据，请先删除绑定数据", sysPermission.getTitle(),
                        sysRoles.stream().map(SysRole::getName).collect(Collectors.toSet())));
            }
        }
        int i = sysPermissionMapper.delBatch(ids);
        if (i == 0) {
            throw new BaseException(Constants.FAIL_DEL);
        }
        delRedisAuthList();
        return i;
    }


    //*****************************递归开始********************************//

    /**
     * 递归开始，找到一级目录
     *
     * @param menuVoList
     * @return
     */
    public List<MenuVo> selectMenuList(List<MenuVo> menuVoList) {
        List<MenuVo> finalMenuList = new ArrayList<>();
        for (MenuVo menuVo : menuVoList) {
            if (menuVo.getParentId() == Constants.MENU_PARENT_ID) {
                finalMenuList.add(selectChildrenList(menuVo, menuVoList));
            }
        }

        return finalMenuList;
    }


    /**
     * 找到一级下的所有子菜单
     *
     * @param menuVo
     * @param menuList
     * @return
     */
    public MenuVo selectChildrenList(MenuVo menuVo, List<MenuVo> menuList) {
        menuVo.setChildren(new ArrayList<>());
        for (MenuVo menu : menuList) {
            if (menu.getParentId().equals(menuVo.getId())) {
                if (menuVo.getChildren() == null) {
                    menuVo.setChildren(new ArrayList<>());
                }
                menuVo.getChildren().add(selectChildrenList(menu, menuList));
            }
        }
        return menuVo;
    }

    //*****************************递归结束********************************//
}
